package flca.voicenav.util;

import com.google.android.maps.GeoPoint;

import flca.voicenav.VoiceNavConstants;
import flca.voicenav.model.GpxRoute;
import flca.voicenav.model.TrkPt;

public class GpxRouteHelper implements VoiceNavConstants
{
	private GpxRoute mGpxRoute;
	
	
	public GpxRouteHelper(GpxRoute mGpxRoute) {
		super();
		this.mGpxRoute = mGpxRoute;
	}

	/**
	 * after parsing the xml file, we use this method to enrich the TrkPt corners
	 * with data like segment length, angle etc.
	 */
	public void calcValues() 
	{
		testIfClosed();
		calcMinMaxCoords();
		calcTotalDistance();
		calcDistances();
		calcAngles();
		findAllCorners();
	}

	private void testIfClosed() 
	{
		double d = calcdist(mGpxRoute.getTrkPt(0), mGpxRoute.getTrkPt(mGpxRoute.size()-1));
		mGpxRoute.setClosed(d < VoiceNavConstants.MIN_NAVPNT_DIST);
	}
	
	/** 
	 * sets the lower-left + upper-right values
	 */
	private void calcMinMaxCoords()
	{
		Double minLat=null, maxLat=null, minLng=null, maxLng=null;
		
		for (TrkPt pt : mGpxRoute.getCoordinates()) {
			if (minLat == null || pt.getLat() < minLat.doubleValue() ) {
				minLat = pt.getLat();
			}
			if (maxLat == null || pt.getLat() > maxLat.doubleValue() ) {
				maxLat = pt.getLat();
			}
			if (minLng == null || pt.getLng() < minLng.doubleValue() ) {
				minLng = pt.getLng();
			}
			if (maxLng == null || pt.getLng() > maxLng.doubleValue() ) {
				maxLng = pt.getLng();
			}
		}
		
		mGpxRoute.setMinLat(minLat);
		mGpxRoute.setMaxLat(maxLat);
		mGpxRoute.setMinLng(minLng);
		mGpxRoute.setMaxLng(maxLng);
	}

	/** 
	 * set the total distance
	 */
	private void calcTotalDistance()
	{
		double dist = 0.0;
		
		for (int i = 1; i < mGpxRoute.size(); i++) {
			dist = dist + calcdist(mGpxRoute.getCoordinates().get(i-1), 
					mGpxRoute.getCoordinates().get(i));
		}
		
		mGpxRoute.setTotalDistance(dist);
	}

	/** 
	 * set per TrkPt the segment distance
	 */
	private void calcDistances()
	{
		for (int i=1; i < mGpxRoute.size()-1; i++) {
			TrkPt p1 = mGpxRoute.getTrkPt(i-1);
			TrkPt p2 = mGpxRoute.getTrkPt(i);
			int dist = (int) (calcdist(p1, p2));
			p1.setDistance(dist);
		}
	}

	/** 
	 * calc the angle between this and the next segment
	 */
	private void calcAngles() 
	{
		for (int i=1; i < mGpxRoute.size()-1; i++) {
			GeoPoint p1 = mGpxRoute.getTrkPt(i-1).toGeoPoint();
			GeoPoint p2 = mGpxRoute.getTrkPt(i).toGeoPoint();
			GeoPoint p3 = mGpxRoute.getTrkPt(i+1).toGeoPoint();
			double angle = DistHelper.calcAngle(p1, p2, p3);
			
			mGpxRoute.getTrkPt(i).setSayAngle(GetNaturalDirection.getAngleAsString(angle));
			mGpxRoute.getTrkPt(i).setAngle(angle);
		}		
	}
	
	/**
	 * this will deduct if a TrkPt is consider a node, where we could notify the user.
	 * This depens on the angle and the prev segment length. 
	 */
	private void findAllCorners()
	{
		mGpxRoute.getTrkPt(0).setCorner(true);
		mGpxRoute.getTrkPt(mGpxRoute.size()-1).setCorner(true);
		
		for (int i=1; i < mGpxRoute.size()-1; i++) {
			TrkPt thisTp = mGpxRoute.getTrkPt(i);
			TrkPt prevTp = mGpxRoute.getTrkPt(i-1);
			int angle = (int) (Math.abs(thisTp.getAngle()));
			
			mGpxRoute.getTrkPt(i).setCorner(angle > MIN_NOTIFY_ANGLE && 
											prevTp.getDistance() > MIN_NOTIFY_DIST);
		}
	}
	
	private double calcdist(TrkPt p1, TrkPt p2) {
		return DistHelper.distance(p1.toGeoPoint(), p2.toGeoPoint(), LengthUnit.METER);
	}
			
}